package widgets

import (
	"image"
	"image/color"
	"image/draw"

	"code.google.com/p/jnj/graphics"
)

const (
	barwidth = 12
)

type Scrollable interface {
	Scroll(step int)
	ScrollTo(pos int)
	ScrollState() (int, int, int)
	Bounds() image.Rectangle
}

type Scrollbar struct {
	// For the convenience of the client. Set to true by NewScrollbar and
	// then never altered again by this package.
	Dirty bool

	elem      Scrollable
	img       *image.RGBA
	bgcol     *image.Uniform
	slidercol *image.Uniform
}

func NewScrollbar(elem Scrollable) *Scrollbar {
	r := image.Rect(0, 0, barwidth, elem.Bounds().Dy())
	sb := &Scrollbar{
		Dirty:     true,
		elem:      elem,
		img:       image.NewRGBA(r),
		bgcol:     image.NewUniform(color.RGBA{R: 0x99, G: 0x99, B: 0x4C, A: 0xFF}),
		slidercol: image.NewUniform(color.RGBA{R: 0xFF, G: 0xFF, B: 0xEA, A: 0xFF}),
	}
	return sb
}

func (sb *Scrollbar) Bounds() image.Rectangle {
	return sb.img.Bounds()
}

// Event returns true if the Scrollable associated with the Scrollbar
// needs to be redrawn.
func (sb *Scrollbar) Event(e *graphics.MouseEvent) {
	y := e.Y - sb.elem.Bounds().Min.Y
	if y < 0 {
		y = 0
	}

	// the percentage of the scrollbar above the click
	percent := float64(y) / float64(sb.Bounds().Dy())

	// the height in steps of visible portion of the Scrollable
	max := float64(sb.elem.Bounds().Dy() / 12)

	switch e.Buttons {
	case 1:
		step := -1 * int(1.0+percent*max)
		sb.elem.Scroll(step)
	case 2:
		current, max, _ := sb.elem.ScrollState()
		pos := int(percent*float64(max)) - 1
		if pos == current {
			return
		}
		sb.elem.ScrollTo(pos)
	case 4:
		step := int(1.0 + percent*max)
		sb.elem.Scroll(step)
	}
}

func (sb *Scrollbar) Draw() *image.RGBA {
	// background
	draw.Draw(sb.img, sb.img.Rect, sb.bgcol, image.ZP, draw.Src)

	// slider
	current, max, stepsize := sb.elem.ScrollState()
	winratio := float64(sb.elem.Bounds().Dy()) / float64(max*stepsize)
	slidersize := int(float64(sb.elem.Bounds().Dy()) * winratio)
	r := sb.img.Rect
	r.Min.Y = int((float64(current) / float64(max)) * float64(sb.elem.Bounds().Dy()))
	r.Max.Y = r.Min.Y + slidersize
	r.Max.X -= 1
	draw.Draw(sb.img, r, sb.slidercol, image.ZP, draw.Src)

	return sb.img
}
